package bit;

import java.io.*;
import java.util.HashMap;

/**
 * @author ZJX
 * @version 1.0
 * @descption
 * @since 2025/11/21 14:37
 */
public class Day30 {
//    public static void main(String[] args) throws IOException {
//        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//        PrintWriter out = new PrintWriter(System.out);
//        in.nextToken();
//        int T = (int) in.nval;
//        while (T-- > 0) {
//            in.nextToken();
//            long a = (long) in.nval;
//            in.nextToken();
//            long b = (long) in.nval;
//            if (a == 1) {
//                out.println(isPrime(b) ? "YES" : "NO");
//            } else if (b == 1) {
//                out.println(isPrime(a) ? "YES" : "NO");
//            } else {
//                out.println("NO");
//            }
//        }
//        out.close();
//    }

    private static boolean isPrime(long n) {
        if (n <= 1) {
            return false;
        }
        if (n == 2) {
            return true;
        }
        if (n % 2 == 0) {
            return false;
        }
        long sqrt = (long) Math.sqrt(n);
        for (int i = 3; i <= sqrt; i += 2) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }

//    public static void main(String[] args) throws IOException {
//        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//        PrintWriter out = new PrintWriter(System.out);
//        in.nextToken();
//        int n = (int) in.nval;
//        in.nextToken();
//        int k = (int) in.nval;
//        int[] nums = new int[n];
//        for (int i = 0; i < n; i++) {
//            in.nextToken();
//            nums[i] = (int) in.nval;
//        }
//        Arrays.sort(nums);
//        if (nums[n - 1] - nums[0] <= k) {
//            out.println(n);
//            out.close();
//            return;
//        }
//        int maxCount = 0;
//        // 二分找到第一个大于等于target的索引下标
//        for (int i = 0; i < n; i++) {
//            int target = nums[i] + k;
//            int left = 0, right = n;
//            while (right > left) {
//                int mid = left + (right - left) / 2;
//                if (nums[mid] > target) {
//                    right = mid;
//                } else {
//                    left = mid + 1;
//                }
//            }
//            maxCount = Math.max(maxCount, left - i);
//        }
//        out.println(maxCount);
//        out.close();
//    }

    /**
     * 最长严格上升子序列
     *
     * @param nums int整型一维数组 给定的数组
     * @return int整型
     */
    public int LIS(int[] nums) {
        int n = nums.length;
        int[] tail = new int[n];
        int maxLen = 0;
        for (int num : nums) {
            int left = 0, right = maxLen;
            while (right > left) {
                int mid = left + (right - left) / 2;
                if (tail[mid] >= num) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            tail[left] = num;
            if (left == maxLen) {
                maxLen++;
            }
        }
        return maxLen;
    }

    public int findNumberOfLIS(int[] nums) {
        int n = nums.length;
        int[] dpLen = new int[n];
        int[] dpCot = new int[n];
        for (int i = 0; i < n; i++) {
            dpLen[i] = 1;
            dpCot[i] = 1;
        }
        int max = 1;
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    if (dpLen[j] + 1 > dpLen[i]) {
                        dpLen[i] = dpLen[j] + 1;
                        dpCot[i] = dpCot[j];
                    } else if ((dpLen[j] + 1) == dpLen[i]) {
                        dpCot[i] += dpCot[j];
                    }
                }
            }
            if (dpLen[i] > max) {
                max = dpLen[i];
            }
        }
        int ret = 0;
        for (int i = 0; i < n; i++) {
            if (max == dpLen[i]) {
                ret += dpCot[i];
            }
        }
        return ret;
    }

    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(System.out);
        in.nextToken();
        int m = (int) in.nval;
        in.nextToken();
        int n = (int) in.nval;
        // 1. 状态定义：dp[i][j] = text1前i个 和 text2前j个 的LCS长度
        int[][] dp = new int[m + 1][n + 1];
        in.nextToken();
        char[] arr1 = in.sval.toCharArray();
        in.nextToken();
        char[] arr2 = in.sval.toCharArray();
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (arr1[i - 1] == arr2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        out.println(dp[m][n]);
        out.close();
    }

    class LRUCache {
        class Node {
            int key, value;
            Node prev, next;

            public Node(int k, int v) {
                key = k;
                value = v;
            }
        }

        private HashMap<Integer, Node> map;
        private Node tail;
        private Node head;
        private int capacity;

        public LRUCache(int capacity) {
            this.capacity = capacity;
            map = new HashMap<>();
            tail = new Node(-1, -1);
            head = new Node(-1, -1);
            head.next = tail;
            tail.prev = head;
        }

        public int get(int key) {
            if (!map.containsKey(key)) {
                return -1;
            }
            Node node = map.get(key);
            remove(node);
            insertHead(node);
            return node.value;
        }

        public void put(int key, int value) {
            if (map.containsKey(key)) {
                Node node = map.get(key);
                node.value = value;
                remove(node);
                insertHead(node);
                return;
            }
            if (map.size() == capacity) {
                Node lru = tail.prev;
                remove(lru);
                map.remove(lru.key);
            }
            Node node = new Node(key, value);
            insertHead(node);
            map.put(key, node);
        }

        private void remove(Node node) {
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }

        private void insertHead(Node node) {
            node.next = head.next;
            head.next.prev = node;
            head.next = node;
            node.prev = head;
        }
    }


    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int cur = nums[0];
        for (int i = 1; i < nums.length; i++) {
            cur = Math.max(cur + nums[i], nums[i]);
            max = Math.max(max, cur);
        }
        return max;
    }

    public int bestTiming(int[] prices) {
        if (prices.length == 0) {
            return 0;
        }
        int min = prices[0];
        int max = 0;
        for (int i = 1; i < prices.length; i++) {
            min = Math.min(min, prices[i]);
            max = Math.max(max, prices[i] - min);
        }
        return max;
    }

    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        int left = 0;
        int ret = 0;
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (map.containsKey(ch)) {
                left = Math.max(left, map.get(ch) + 1);
            }
            map.put(ch, i);
            ret = Math.max(ret, i - left + 1);
        }
        return ret;
    }

}

